package com.ztesoft.book.admin.controller.sys;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.PageInfo;
import com.ztesoft.book.admin.annotation.SysLog;
import com.ztesoft.book.admin.controller.base.BaseController;
import com.ztesoft.book.common.enums.IntEnum;
import com.ztesoft.book.common.utils.Result;
import com.ztesoft.book.common.utils.encrypt.AesEncryptSm4Util;
import com.ztesoft.book.common.utils.encrypt.RSAUtil;
import com.ztesoft.book.common.utils.exception.ExUtil;
import com.ztesoft.book.common.utils.exception.ServiceException;
import com.ztesoft.book.common.utils.validator.ValidatorUtils;
import com.ztesoft.book.core.base.base.enums.ResultEnum;
import com.ztesoft.book.core.sys.sysmenu.qo.LoginMenuTreeNewQO;
import com.ztesoft.book.core.sys.sysuser.dto.SysUserDTO;
import com.ztesoft.book.core.sys.sysuser.qo.SysLoginEncryptedQO;
import com.ztesoft.book.core.sys.sysuser.qo.SysUserQO;
import com.ztesoft.book.core.sys.sysuser.service.SysUserService;
import com.ztesoft.book.core.sys.sysuser.vo.SysUserPwdVO;
import com.ztesoft.book.core.sys.sysuser.vo.SysUserSafeVO;
import com.ztesoft.book.core.sys.sysuser.vo.SysUserStatusVO;
import com.ztesoft.book.core.sys.sysuser.vo.SysUserVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description 用户控制类
 * @Author YangFan
 * @Date 2021-06-22 17:07
 */
@RestController
@RequestMapping("/sys/sysuser")
@RequiresPermissions("sysuser:")
@Slf4j
public class SysUserController extends BaseController<SysUserService, SysUserDTO, SysUserQO> {

    public static final String SYSTEM_ROLE = "1";


    @Value("${book.user.defaultPwd}")
    private String defaultPwd;

    @Resource
    private SysUserService sysUserService;

    @Override
    protected SysUserService getService() {
        return sysUserService;
    }

    @Override
    protected void handleBeforeUpdateObject(SysUserDTO sysUserDTO) {
        // 修改前方法--不可修改密码
        sysUserDTO.setPassword(null);
        sysUserDTO.setModifyPwd(null);
    }


    @Override
    protected void handleBeforeFindPage(SysUserQO qo) {
        // 查找分页列表前方法
        if (!StringUtils.isBlank(qo.getUsername())) {
            qo.setUsername(AesEncryptSm4Util.encrypt(qo.getUsername()));
        }
        SysUserDTO loginUser = getShiroUser();
    }


    @Override
    @PostMapping("/findPage")
    public @ResponseBody
    Result findPage(@RequestBody SysUserQO qo) {
        try {
            if (qo.getCurrent() == null || qo.getPageSize() == null) {
                throw new ServiceException("分页参数不能为空");
            }
            int integerCurrent = qo.getCurrent();
            int integerPageSize = qo.getPageSize();

            handleBeforeFindPage(qo);

            // 越权查询检测
            if (!checkUserName(qo)) {
                return Result.error("无权查询！");
            }

            PageInfo<SysUserSafeVO> pageInfo = sysUserService.findPageSafe(qo, integerCurrent, integerPageSize);
            Map<String, Object> rtnMap = new HashMap<>(16);
            rtnMap.put("pageSize", pageInfo.getPageSize());
            rtnMap.put("total", pageInfo.getTotal());
            rtnMap.put("pages", pageInfo.getPages());
            rtnMap.put("current", pageInfo.getPageNum());
            rtnMap.put("list", pageInfo.getList());

            return Result.success(rtnMap);
        }
        catch (NumberFormatException numberFormatException) {
            return Result.error("参数不合法！");
        }
        catch (Exception e) {
            log.error("查询失败", e);
            return Result.error("查询失败");
        }
    }


    /**
     * 方法功能描述:
     * < username权限范围检测 >
     *
     * @param qo 参数说明
     * @return boolean
     * @author YangFan
     * @date 2021-08-06 20:57
     */
    private boolean checkUserName(SysUserQO qo) {
        SysUserQO userNameQO = new SysUserQO();
        if (StringUtils.isBlank(qo.getUsername())) {
            return true;
        }
        userNameQO.setUsername(qo.getUsername());
        SysUserDTO checkUser = sysUserService.findOne(userNameQO);
        SysUserDTO nowUser = getShiroUser();
        if (checkUser == null) {
            return false;
        }
        return true;
    }


    @PostMapping("/updatePwd")
    public Result updatePwd(@RequestBody SysUserPwdVO sysUserPwdVO) {
        SysUserDTO loginUser = getShiroUser();
        sysUserPwdVO.setId(loginUser.getId());
        // 校验表单数据
        ValidatorUtils.validateEntity(sysUserPwdVO);
        try {
            this.getService()
                    .updatePwd(sysUserPwdVO);
            return Result.success("修改成功");
        }
        catch (ServiceException ex) {
            return Result.error(ex.getMessage());
        }
        catch (Exception ex) {
            log.error(ex.getMessage());
            return Result.error("修改失败！");
        }
    }

    @PostMapping("/updatePwd_encrypted")
    public Result updatePwdEncrypted(@RequestBody SysLoginEncryptedQO qo) {
        SysUserPwdVO userPwdVO = RSAUtil.getDecodeObj(qo.getJsonData(), qo.getPublicKey(), SysUserPwdVO.class);
        if (userPwdVO != null) {
            return this.updatePwd(userPwdVO);
        }
        else {
            return Result.error("参数解密错误");
        }

    }

    /**
     * 方法功能描述:
     * < 新增用户 >
     *
     * @param sysUserDTO 【参数 1 注释说明】
     * @return Result                        【返回值 注释说明】
     * @author YangFan
     * @date 2021-06-24 17:02
     */
    @PostMapping("/addNewUser")
    @RequiresPermissions("save")
    public Result addNewUser(@RequestBody SysUserDTO sysUserDTO) {

        sysUserDTO.setPassword(AesEncryptSm4Util.desEncrypt(defaultPwd));

        //防止空格
        if (StringUtils.isNotBlank(sysUserDTO.getUsername())) {
            String username = sysUserDTO.getUsername().replaceAll(" ", "");
            sysUserDTO.setUsername(username);
        }

        // 校验表单数据
        ValidatorUtils.validateEntity(sysUserDTO);


        // 获取当前登录用户（测试，没用到）
        SysUserDTO loginUser = getShiroUser();
        // 判断当前帐号是否存在
        SysUserQO param = new SysUserQO();
        param.setUsername(AesEncryptSm4Util.encrypt(sysUserDTO.getUsername()));
        SysUserDTO userDtoTemp = sysUserService.findOne(param);
        if (userDtoTemp != null) {
            throw new ServiceException("该用户名已存在!");
        }

        String username = sysUserDTO.getUsername();

        // 账号已EXT方式加密保存
        sysUserDTO.setUsername(AesEncryptSm4Util.encrypt(username));

        // 密码以 帐号(salt)+密码 的形式进行SM3加密
        String salt = RandomUtil.randomStringUpper(6);
        String key = SmUtil.sm3(salt + sysUserDTO.getPassword());
        sysUserDTO.setPassword(key);
        sysUserDTO.setModifyPwd(0);
        sysUserDTO.setSalt(salt);

        sysUserService.saveObject(sysUserDTO);

        return Result.success("新增用户成功！", sysUserDTO);
    }


    /**
     * 方法功能描述:
     * < 获取当前登录用户的菜单 >
     *
     * @return Result                        【返回值 注释说明】
     * @author YangFan
     * @date 2021-07-02 14:53
     */
    @SysLog("获取当前登录用户的菜单")
    @PostMapping("/getLoginUserMenu")
    public Result getLoginUserMenu() {
        // 获取当前登录用户
        SysUserDTO loginUser = getShiroUser();
        List<LoginMenuTreeNewQO> menulist = sysUserService.getLoginUserMenuByUserNew(loginUser.getId());
        return Result.success("登录菜单加载成功", menulist);
    }

    /**
     * 启用/停用
     *
     * @param vo vo
     * @return
     * @date 2021-07-13 14:12
     */
    @PostMapping("/updateStatus")
    public Result updateStatus(@RequestBody SysUserStatusVO vo) {
        ValidatorUtils.validateEntity(vo);
        try {
            UpdateWrapper<SysUserDTO> wrapper = new UpdateWrapper<>();
            wrapper.lambda()
                    .eq(SysUserDTO::getId, vo.getId())
                    .set(SysUserDTO::getStatus, vo.getStatus());
            sysUserService.update(wrapper);
            return Result.success("操作成功");
        }
        catch (Exception e) {
            log.error("用户启用/停用失败", e);
            return Result.success("操作失败");
        }
    }

    /**
     * 解锁
     *
     * @param id id
     * @return
     * @date 2021-07-13 14:12
     */
    @PostMapping("/unlockUser")
    public Result unlockUser(@RequestBody String id) {
        ExUtil.checkArgument(StrUtil.isNotBlank(id), "用户id不能为空");
        try {
            UpdateWrapper<SysUserDTO> wrapper = new UpdateWrapper<>();
            wrapper.lambda()
                    .eq(SysUserDTO::getId, id)
                    .set(SysUserDTO::getWrongPwdTimes, IntEnum.ZERO.getValue())
                    .set(true, SysUserDTO::getUserLockTime, null);
            sysUserService.update(wrapper);
            return Result.success("解锁成功");
        }
        catch (Exception e) {
            log.error("解锁失败", e);
            return Result.success("解锁失败");
        }
    }

    /**
     * 获取用户信息
     *
     * @param id
     * @return
     */
    @Override
    public Result findById(@NotBlank String id) {
        SysUserDTO data = (SysUserDTO) super.findById(id)
                .get("data");
        SysUserVO sysUserVO = new SysUserVO();
        sysUserVO.setUsername(AesEncryptSm4Util.desEncrypt(data.getUsername()));
        sysUserVO.setLogo(data.getLogo());
        return Result.success(sysUserVO);
    }

    /**
     * 首页个人信息
     *
     * @return
     */
    @PostMapping("/getUserDetail")
    public Result getUserDetail() {
        try {
            SysUserDTO sysUserDTO = getShiroUser();
            SysUserVO sysUserVO = new SysUserVO();
            sysUserVO.setUsername(AesEncryptSm4Util.desEncrypt(sysUserDTO.getUsername()));
            sysUserVO.setLogo(sysUserDTO.getLogo());
            sysUserVO.setNickName(sysUserDTO.getNickName());
            return Result.success(sysUserVO);
        }
        catch (ServiceException e) {
            log.error("getUserDetail:{}", e);
            return Result.error(ResultEnum.FAIL.getMsg());
        }
        catch (Exception e) {
            log.error("getUserDetail:{}", e);
            return Result.error(ResultEnum.FAIL.getMsg());
        }
    }
}
